package pcloud.client.watcher;

import java.io.File;
import java.io.UnsupportedEncodingException;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import pcloud.client.scheduler.TaskScheduler;
import pcloud.client.util.FileResourceInfo;
import pcloud.client.util.Logger;
import pcloud.client.util.TreeDB;
import pcloud.client.util.TreeNode;
import pcloud.client.worker.CloudTask;
import pcloud.client.worker.RemoteCreateTask;
import pcloud.client.worker.RemoteDeleteTask;
import pcloud.client.worker.TaskMonitor;
import pcloud.client.worker.UploadTask;

public class PollClientWatcherNode implements TreeNode
{
    private TaskScheduler taskScheduler;
	private File targetFile;
	private String targetFilePath;
	private PollClientWatcher watcher;
	private TreeDB<FileResourceInfo> fileInfoDB;
	private String watchRoot;

//	private PollWatcherNode(PollClientWatcher watcher, File targetFile)
//	{
//		this.watcher = watcher;
//		fileInfoDB = watcher.getLocalDB();
//		monitor = watcher.getMonitor();
//		this.targetFile = targetFile;
//		this.targetFilePath = targetFile.getPath();
//	}
//
//	private PollWatcherNode(PollClientWatcher watcher, String targetFilePath)
//	{
//		this(watcher, new File(targetFilePath) ); 
//	}

	public PollClientWatcherNode(PollClientWatcher watcher, File targetFile, String watchRoot)
	{
		this.watcher = watcher;
		fileInfoDB = watcher.getLocalDB();
        this.taskScheduler = watcher.getScheduler();
		this.targetFile = targetFile;
		this.targetFilePath = targetFile.getPath().replace('\\', '/');
		this.watchRoot = watchRoot;
	}

	public PollClientWatcherNode(PollClientWatcher watcher, String targetFilePath, String watchRoot)
	{
		this(watcher, new File(targetFilePath), watchRoot ); 
	}

	@Override
	public Collection<TreeNode> getChildNodes()
	{
		Map<String, TreeNode> childNodesMap =   new HashMap<String, TreeNode>();
		File[] childFiles = targetFile.listFiles();
		
		for (File childFile : childFiles) {
			childNodesMap.put(childFile.getPath().replace('\\', '/'), new PollClientWatcherNode(watcher, childFile, this.watchRoot));
		}
		
		//check if there is any file was deleted.
		List<FileResourceInfo> oldChildNodes = fileInfoDB.getChild(targetFilePath);
		
		for (FileResourceInfo oldChildNode : oldChildNodes) {
			String oldChildFilePath = oldChildNode.getFullPath();
			if (! childNodesMap.containsKey(oldChildFilePath)) {
				logger.info("before create a remote delete task! "+oldChildNode.toString());
				CloudTask task = new RemoteDeleteTask(oldChildNode.toRemote());
				TaskMonitor monitor = new RemoteDeleteMonitor(fileInfoDB);
				task.setMonitor(monitor);
				if (! taskScheduler.add(task) ) {
					logger.info("add a task to the scheduler failed! ");					
				}
			}
		}
		return childNodesMap.values();
	}
	
	@Override
	public boolean isLeaf()
	{
		return !targetFile.isDirectory();
	}

	@Override
	public void visit()
	{
		logger.info("PollWatcherNode.visit, targetFilePath= ["+ 
					targetFilePath+"]");
		
		int changeState = checkChange();
		if (changeState==CHANGE_STATE_UNCHANGED) {
			return;
		}
		
		FileResourceInfo fileInfo = new FileResourceInfo(targetFile, this.watchRoot);
		//文件夹的变化(修改时间的变化)肯定是由于其内容变化引起的, 不需要对其自身做同步操作
		if (changeState==CHANGE_STATE_MODIFIED && fileInfo.isFolder()) {
			return;
		}

		CloudTask task ;
		TaskMonitor monitor ;
		
		if (fileInfo.isFolder() && changeState==CHANGE_STATE_CREATE ) {
			logger.info("before create a remote create task! "+fileInfo.toString());

			task = new RemoteCreateTask(fileInfo.toRemote());
			monitor = new RemoteCreateMonitor(fileInfoDB);
			
		} else {
			logger.info("before create an upload task! "+fileInfo.toString());

			task = new UploadTask(fileInfo);
			monitor = new UploadMonitor(fileInfoDB);
		}
		
		task.setMonitor(monitor);
		if (!taskScheduler.add(task)) {
			logger.info("add a task to the scheduler failed! ");
		}
	}

	private int checkChange()
	{
		FileResourceInfo lastFileInfo = fileInfoDB.get(targetFile.getPath());

		if (lastFileInfo == null) {
			return CHANGE_STATE_CREATE;
		}

		long lastModifiedInDB = lastFileInfo.lastModified();
		long lastModifiedNow = targetFile.lastModified();

		if (lastModifiedNow == lastModifiedInDB) {
			return CHANGE_STATE_UNCHANGED;
		} else {
			return CHANGE_STATE_MODIFIED;
		}
	}

	private static final int CHANGE_STATE_UNCHANGED = 0;
	private static final int CHANGE_STATE_CREATE = 1;
	private static final int CHANGE_STATE_MODIFIED = 2;

	public void initialize()
	{
		FileResourceInfo lastFileInfo = fileInfoDB.get(targetFilePath);
		if (lastFileInfo == null) {
			fileInfoDB.put(targetFilePath, new FileResourceInfo(targetFile), true);
		}
	}
}
